package cn.kgc.service;

import cn.kgc.client.*;
import cn.kgc.dto.Dto;
import cn.kgc.dto.DtoUtil;
import cn.kgc.exception.OrderErrorCode;
import cn.kgc.pojo.*;
import cn.kgc.util.RedisUtil;
import cn.kgc.utils.BaseException;
import cn.kgc.utils.Constants;
import cn.kgc.utils.EmptyUtils;
import cn.kgc.vo.CreateOrderVo;
import com.example.IdWorker;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {


    @Autowired
    RestDmItemClient restDmItemClient;

    @Autowired
    RestDmSchedulerSeatClient restDmSchedulerSeatClient;

    @Autowired
    RestDmSchedulerSeatPriceClient restDmSchedulerSeatPriceClient;

    @Autowired
    RestDmOrderClient restDmOrderClient;

    @Autowired
    RestDmLinkUserClient restDmLinkUserClient;

    @Autowired
    RestDmOrderLinkUserClient restDmOrderLinkUserClient;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    RabbitTemplate rabbitTemplate;

    //多个线程同时下单？
    // 1.甲乙丙  同一个排期，同一个座位---? ----------->
    @Override
    public synchronized Dto  createOrder(CreateOrderVo createOrderVo) throws Exception {

        //1.查询对应的商品信息，如果不存在节目信息，抛异常
        DmItem dmItemById = restDmItemClient.getDmItemById(createOrderVo.getItemId());
        if (EmptyUtils.isEmpty(dmItemById)) {
            throw new BaseException(OrderErrorCode.OREER_ARGS_ERROR);
        }

        //添加分布式锁，解决线程抢占资源问题，实现数据的同步处理
        while(!redisUtil.lock(String.valueOf(createOrderVo.getSchedulerId()))) {
            //没抢到资源
            TimeUnit.SECONDS.sleep(500);
        }

        //2.生成唯一的订单号
        Long orderNo = IdWorker.getId();

        //3.获取前端传过来的座位，查询座位对应的价格，求得总价
        String seatPositions = createOrderVo.getSeatPositions();
        //数组里面装了座位 x1_y1  x2_y2  x3_y3-------》 1_1, 2_2, 3_3
        String[] split = seatPositions.split(",");
        java.util.List<DmSchedulerSeat> bookSeats=new ArrayList<>();
        java.util.List<DmSchedulerSeatPrice> bookSeatsprices=new ArrayList<>();

        double totalSeatPrice=0;
        for (int i = 0; i < split.length; i++) {
            String s = split[i];
            String[] xy = s.split("_");
            String x = xy[0];
            String y=  xy[1];
            //拿到座位的x,y的值
            java.util.Map map = new HashMap<String,Object>();
            map.put("x",x);
            map.put("y",y);
            map.put("scheduleId",createOrderVo.getSchedulerId());
            DmSchedulerSeat dmSchedulerSeat = (DmSchedulerSeat)( restDmSchedulerSeatClient.getDmSchedulerSeatListByMap(map).get(0));
            if (dmSchedulerSeat.getStatus()!= Constants.SchedulerSeatStatus.SchedulerSeat_FREE) {
                redisUtil.unlock(String.valueOf(createOrderVo.getSchedulerId()));
                throw new BaseException(OrderErrorCode.No_ALIDSEAT);
            }
            bookSeats.add(dmSchedulerSeat);
        }

        //4.更新用户所选的座位的状态（锁住座位状态，待支付）     1--dm_scheduler_seat
        try {
            for (DmSchedulerSeat bookSeat : bookSeats) {

                bookSeat.setStatus(Constants.SchedulerSeatStatus.SchedulerSeat_TOPAY);
                bookSeat.setOrderNo(orderNo + "");
                bookSeat.setUserId(createOrderVo.getUserId());
                //甲  乙
                restDmSchedulerSeatClient.qdtxModifyDmSchedulerSeat(bookSeat);
                Integer areaLevel = bookSeat.getAreaLevel();
                java.util.Map map = new HashMap<String, Object>();
                map.put("scheduleId", createOrderVo.getSchedulerId());
                map.put("areaLevel", areaLevel);
                DmSchedulerSeatPrice dmSchedulerSeatPrice = (DmSchedulerSeatPrice) (restDmSchedulerSeatPriceClient.getDmSchedulerSeatPriceListByMap(map).get(0));
                bookSeatsprices.add(dmSchedulerSeatPrice);
                totalSeatPrice += dmSchedulerSeatPrice.getPrice();
            }
        }catch (Exception e){
            e.printStackTrace();
            redisUtil.unlock(String.valueOf(createOrderVo.getSchedulerId()));
            //异常处理
            //回滚 座位锁定状态需要回滚，释放锁资源
            sendResetSeatStatus(bookSeats);
            throw e;
        }

        //修改订单表
        DmOrder order=new DmOrder();
        order.setItemId(createOrderVo.getItemId());
        order.setSchedulerId(createOrderVo.getSchedulerId());
        order.setOrderNo(orderNo+"");
        order.setItemName(dmItemById.getItemName());
        order.setOrderType(Constants.OrderStatus.TOPAY);
       // order.setUserId(createOrderVo.getUserId());
        if (createOrderVo.getIsNeedInvoice()!=null&&createOrderVo.getIsNeedInvoice()==1) {
            order.setInvoiceHead(createOrderVo.getInvoiceHead());
            order.setInvoiceNo(createOrderVo.getInvoiceNo());
            order.setInvoiceType(createOrderVo.getInvoiceType());
            order.setIsNeedInvoice(createOrderVo.getIsNeedInvoice());
        }

        //商品的数量
        order.setTotalCount(bookSeats.size());


        //5.如果勾选了保险，增加到订单中  ，总价
        double insuranceprice=0;
        if(createOrderVo.getIsNeedInsurance()==Constants.OrderStatus.ISNEEDINSURANCE_YES){
           insuranceprice= Constants.OrderStatus.NEEDINSURANCE_MONEY*bookSeats.size();
           order.setIsNeedInsurance(createOrderVo.getIsNeedInsurance());
        }

        order.setTotalAmount(insuranceprice+totalSeatPrice);
        order.setCreatedTime(new Date());
        Integer orderId=-1;
        try {
            //6.生成订单信息                                   2---dm_order
           orderId= restDmOrderClient.qdtxAddDmOrder(order);
        }catch (Exception e){
            //异常
            redisUtil.unlock(String.valueOf(createOrderVo.getSchedulerId()));
            //怎么办？
            //释放锁资源
            //事务回滚（座位待支付状态回滚---》改回 可预定状态）
            sendResetSeatStatus(bookSeats);
        }

        //7查询订单有关的用户，需要更新相关的关联用户信息        3----dm_order_link_user
        String[] linkIds = createOrderVo.getLinkIds().split(",");
        for (int i = 0; i < linkIds.length; i++ ) {
            //获取相关联系人
            try{
             DmLinkUser dmLinkUserById = restDmLinkUserClient.getDmLinkUserById(Long.parseLong(linkIds[i]));
            if(dmLinkUserById==null){
                 throw  new BaseException(OrderErrorCode.NO_ORDER_LINKEDUSER);
            }
            //封装订单的相关联系人信息，插入到订单的联系人表中
            DmOrderLinkUser dmOrderLinkUser=new DmOrderLinkUser();
            dmOrderLinkUser.setOrderId(new Long(orderId));
            dmOrderLinkUser.setLinkUserName(dmLinkUserById.getName());
            dmOrderLinkUser.setLinkUserId(dmLinkUserById.getId());
            dmOrderLinkUser.setX(bookSeats.get(i).getX());
            dmOrderLinkUser.setY(bookSeats.get(i).getY());
            dmOrderLinkUser.setPrice(bookSeatsprices.get(0).getPrice());
            dmOrderLinkUser.setCreatedTime(new Date());

                restDmOrderLinkUserClient.qdtxAddDmOrderLinkUser(dmOrderLinkUser);

            }catch (Exception e){
                //异常： 事务回滚
                redisUtil.unlock(String.valueOf(createOrderVo.getSchedulerId()));
              //  事务回滚
                //1.  座位锁定需要回滚
                sendResetSeatStatus(bookSeats);
                //2.  插入的订单信息需要回滚 回滾 todo
                sendDelOrder(orderId);
                //3. 相关的订单联系人也要删除干净 回滾 todo
                sendDelOrderLinkedUser(orderId);
                throw e;
            }

        }


        redisUtil.unlock(String.valueOf(createOrderVo.getSchedulerId()));
        //8 将封装好的订单信息保存到数据库
        return DtoUtil.returnDataSuccess(orderNo);
    }

    @Override
    public void fluashCancelOrder() {
        //1.订单状态修改
        restDmOrderClient.flushCancelOrder();
        //2.重置座位的状态 todo 重置座位的状态
        restDmSchedulerSeatClient.flushUpateDmShedulerSeat();
    }

    private void sendDelOrderLinkedUser(Integer orderId) {
        rabbitTemplate.convertAndSend(Constants.RabbitQueueName.TOPIC_EXCHANGE, Constants.RabbitQueueName.TO_RESET_LINKUSER_QUQUE, orderId, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                return message;
            }
        });
    }

    private void sendDelOrder(Integer orderId) {
        rabbitTemplate.convertAndSend(Constants.RabbitQueueName.TOPIC_EXCHANGE, Constants.RabbitQueueName.TO_DEL_ORDER_QUQUE, orderId, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                return message;
            }
        });
    }

    private void sendResetSeatStatus(java.util.List<DmSchedulerSeat> dmSchedulerSeatList){

        java.util.Map map =new HashMap();
        map.put("seats",dmSchedulerSeatList);
        log.info("=======发送重置座位状态的消息放到RabbitMq中=========");
        rabbitTemplate.convertAndSend(Constants.RabbitQueueName.TOPIC_EXCHANGE, Constants.RabbitQueueName.TO_RESET_SEAT_QUQUE, map, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                return message;
            }
        });
    }


}
